Procedure
Prerequisites
- Download
spectre.c
from gist.github.com. - Recompile gem5 in the x86 instruction set. Refer to the tutorial, except instead of
scons build/RISCV/gem5.opt
usescons build/X86/gem5.opt
.
Procedure
Compile the spectre.c
code
You need to perform a bit more specific of a command than normal:
gcc -g spectre.c -o spectre -static
This makes the following modifications to the compiled code:
-g
add debug symbols-static
statically link libraries
This will produce a standalone binary that you can use in the gem5 simulator. In order to run this binary with gem5, we provide the spectre_workload in system.py
Modify the two_level.py
config file
- Change
X86TimingCPU
toX86O3CPU(branchPred=LTAGE())
Generate a Log File
The first task will be to generate a log-file that shows the passage of instructions through the pipeline.
-
Use the following command as tested above then hit ctrl-c after the first 2 letters. Record the tick number that the simulator ended at. For example 13062347000
nice -n 19 $GEM_PATH/build/X86/gem5.opt configs/learning_gem5/part1/two_level.py spectre
-
Run gem5 with the debug flag O3PipeView enabled.
Make sure the debug-start tick matches the tick from step 1.
nice -n 19 $GEM_PATH/build/X86/gem5.opt --debug-flags=O3PipeView --debug-file=pipeview.txt --debug-start=13062347000 configs/learning_gem5/part1/two_level.py spectre
-
Watch the output and stop execution with ctrl-c after two more letters appeared than in step 1. This will create at least two instances of speculative side effects we can observe.
-
Run the pipeline viewer with the generated trace file.
The -w
option specifies the width of the output file so depending on the size of your terminal you may wish to choose a larger or smaller value.
$GEM_PATH/util/o3-pipeview.py --store_completions m5out/pipeview.txt --color -w 100
-
Now finally use the following command to view the generated file showing the instructions moving through the pipeline:
less -r o3-pipeview.out
The timeline section shows time moving from left to right and shows instructions going through the stages of the pipeline with letters indicating the time they entered each stage and dots for each cycle they remain in that stage. For example f....dn.p....ic..r
would represent fetch, wait 4 cycles, decode, rename,wait 1, dispatch, wait 4, issue, commit, wait 2, and retire. l
and s
are used to denote load finishing and store finishing respectively.
The tick column shows the tick of the simulator. The pc.upc column shows the instructions along with their addresses. The disasm column shows the assembly instructions being executed.
time will wrap around if an instruction runs out of room in the timeline column. For example in the following timeline it appears as though issuing, committing and retiring came before fetch, decode and renaming but this is due to the wraparound.
[............ic......r...........................................f.............................dn....]
Match Vulnerable Instructions
Now that the log-file is created we want to match up the instructions executed to the vulnerable section of spectre.c
code. This will be the next task:
The binary generated during installation was compiled with the -g
flag so that it can be disassembled alongside the source. Therefore we can use the following command to create the disassembly:
objdump -S spectre > spectreX86.s
-
Now the disassembly can be examined to find the instruction addresses where speculation is used to leak victim secrets.
tipI would recommend reading over the
spectre.c
source to determine the relevant section and then examinespectreX86.s
to find the address of the relevant instructions. -
Once the section of code has been located, write down the address of the relevant instructions. An address looks like
400c12:
-
With this address we can search the log-file that was generated earlier to find the part of the log-file where leaking occured.
less commandsWhen in the
less
program, you can use vim-style searching:If we wanted to search for our example address, you can type
/400c12
(/
+ your search string) and press enter. This will search the log-file for the string400c12
.If you are in the correct section of the log-file you should see many instructions that contain lines like:
[=====================================f============dn==ic=================================================]
This means that the instruction was squashed due to a misprediction.
-
Attach with your report the disassembly of the vulnerable code
victim_function
taken fromspectreX86.s
and call itvuln.s
. Further attach the section from theo3-pipeview.out
that corresponds to addresses invuln.s
that shows the squashed instructions in the vulnerable section. Call this excerptpipeview-spec.out
-
(2 points) Meeting notes. See the collaboration requirements for what to include.
Postscript
The attack discussed in this lab is known as Spectre Variant 1. There are many other variants that in some way exploit speculation to read values that are off-limits. Some variants of Spectre are significantly much more difficult to mitigate. In the case of variant 1 it is possible to patch by recompiling sensitive applications to avoid the structure below:
if(index < len)
array[expr(index)] //leaky
For example a fence instruction can be inserted to prevent speculation as below. Fence operates by preventing any instructions from being issued until all older instructions have been retired. Thus the access to array
can only happen if index is within bounds.
if(index < len){
fence()
array[expr(index)] //safe
}